import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThanOrEqual, MoreThan } from 'typeorm';
import { Todo } from './entities/todo.entity';

@Injectable()
export class TodoReminderService {
  private readonly logger = new Logger(TodoReminderService.name);
  private notifiedTodos = new Set<number>(); // 记录已经提醒过的任务ID

  constructor(
    @InjectRepository(Todo)
    private readonly todoRepository: Repository<Todo>,
  ) {}

  // 每分钟检查一次即将到期的任务
  @Cron(CronExpression.EVERY_MINUTE)
  async checkUpcomingDueTodos() {
    this.logger.debug('开始检查即将到期的任务...');

    const now = new Date();
    const tenMinutesLater = new Date(now.getTime() + 10 * 60 * 1000); // 10分钟后

    try {
      // 查找在未来10分钟内到期的、未完成的任务
      const upcomingDueTodos = await this.todoRepository.find({
        where: {
          completed: false,
          dueDate: LessThanOrEqual(tenMinutesLater),
        },
        relations: ['creator', 'assignee'],
      });

      // 过滤出还未提醒过且到期时间在未来（不是已经过期的）
      const todosToNotify = upcomingDueTodos.filter((todo) => {
        if (!todo.dueDate) return false;

        const dueTime = new Date(todo.dueDate).getTime();
        const nowTime = now.getTime();
        const timeUntilDue = dueTime - nowTime;

        // 只提醒在未来0-10分钟内到期的任务
        // 且该任务还没有被提醒过
        return (
          timeUntilDue > 0 &&
          timeUntilDue <= 10 * 60 * 1000 &&
          !this.notifiedTodos.has(todo.id)
        );
      });

      if (todosToNotify.length > 0) {
        this.logger.log(`发现 ${todosToNotify.length} 个即将到期的任务`);

        for (const todo of todosToNotify) {
          this.sendReminder(todo);
          this.notifiedTodos.add(todo.id); // 标记为已提醒
        }
      } else {
        this.logger.debug('没有需要提醒的任务');
      }
    } catch (error) {
      this.logger.error('检查到期任务时发生错误:', error);
    }
  }

  // 每小时清理一次已提醒任务列表（清理已完成或已过期的任务）
  @Cron(CronExpression.EVERY_HOUR)
  async cleanupNotifiedTasks() {
    this.logger.debug('清理已提醒任务列表...');

    const now = new Date();
    const notifiedIds = Array.from(this.notifiedTodos);

    if (notifiedIds.length === 0) {
      return;
    }

    try {
      // 查询这些任务的当前状态
      const todos = await this.todoRepository.findByIds(notifiedIds);

      for (const todo of todos) {
        // 如果任务已完成或已过期超过1小时，从提醒列表中移除
        if (
          todo.completed ||
          (todo.dueDate &&
            new Date(todo.dueDate).getTime() < now.getTime() - 60 * 60 * 1000)
        ) {
          this.notifiedTodos.delete(todo.id);
          this.logger.debug(`从提醒列表移除任务 ${todo.id}`);
        }
      }

      this.logger.log(`清理完成，当前提醒列表大小: ${this.notifiedTodos.size}`);
    } catch (error) {
      this.logger.error('清理提醒列表时发生错误:', error);
    }
  }

  /**
   * 发送任务到期提醒
   */
  private sendReminder(todo: Todo) {
    const dueDate = new Date(todo.dueDate);
    const now = new Date();
    const minutesUntilDue = Math.round(
      (dueDate.getTime() - now.getTime()) / (1000 * 60),
    );

    const assigneeName = todo.assignee?.name || '未分配';
    const creatorName = todo.creator?.name || '未知';

    this.logger.warn(
      `
┌─────────────────────────────────────────────────────────────┐
│                    🔔 任务到期提醒                           │
├─────────────────────────────────────────────────────────────┤
│ 任务ID: ${todo.id}
│ 标题: ${todo.title}
│ 负责人: ${assigneeName}
│ 创建人: ${creatorName}
│ 预计完成时间: ${dueDate.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
      })}
│ 剩余时间: ${minutesUntilDue} 分钟
└─────────────────────────────────────────────────────────────┘
`,
    );
  }

  /**
   * 当任务被标记为完成时，从提醒列表中移除
   */
  removeFromNotifiedList(todoId: number) {
    this.notifiedTodos.delete(todoId);
    this.logger.debug(`任务 ${todoId} 已完成，从提醒列表移除`);
  }

  /**
   * 当任务的到期时间被更新时，从提醒列表中移除（重新计算提醒时间）
   */
  resetNotification(todoId: number) {
    this.notifiedTodos.delete(todoId);
    this.logger.debug(`任务 ${todoId} 的到期时间已更新，重置提醒状态`);
  }
}
